import logger from '../utils/logger.js'
class CodeTrajectoryValidator {
  constructor() {
      this.commands = [
          'pen', 'fd', 'bk', 'rt', 'lt', 'up', 'down', 'size', 'c', 'cls', 
          'speed', 'show', 'hide', 'text', 'testSize', 'font', 'setprecision',
          'for', 'if', 'wait', 'cin>>', 'cinWin', 'cout<<', 'cout<<endl', 
          'cout<<setprecision', 'o', 'oo', 'e', 'ee', 'r', 'rr', 'moveto', 'lineto'
      ];
      
      this.state = {
          x: 0,
          y: 0,
          angle: 0, // 角度，0度表示向右
          penDown: true,
          color: 'black',
          size: 1,
          speed: 1,
          visible: true,
          precision: 2
      };
      
      this.trajectory = [];
      this.points = [];
  }
  
  // 主验证函数
  validate(userCode, answerCode, options = {}) {
      const defaultOptions = {
          tolerance: 0.1,           // 点位置容忍度
          angleTolerance: 5,        // 角度容忍度
          requireExactPath: false,  // 是否要求完全相同的路径
          maxPoints: 1000,          // 最大轨迹点数
          isRegular: 0,             // 判题模式：0=宽松模式，1=严格模式（指令顺序不敏感）
          ...options
      };
      
      try {
          // 解析并执行代码，生成轨迹
          const userTrajectory = this.executeCode(userCode);
          const answerTrajectory = this.executeCode(answerCode);
          
          // 比较轨迹
          const result = this.compareTrajectories(
              userTrajectory, 
              answerTrajectory, 
              defaultOptions
          );
    
    return {
              isValid: result.isValid,
              similarity: result.similarity,
              userPoints: userTrajectory.points.length,
              answerPoints: answerTrajectory.points.length,
              details: result.details,
              error: null
          };
          
  } catch (error) {
    return {
              isValid: false,
              similarity: 0,
              userPoints: 0,
              answerPoints: 0,
              details: { error: error.message },
      error: error.message
    };
  }
}

  // 执行代码并生成轨迹
  executeCode(code) {
      this.resetState();
      
      // 预处理代码：处理for循环、if语句等
      const processedCode = this.preprocessCode(code);
      
      // 分割代码为令牌
      const tokens = this.tokenize(processedCode);
      
      // 执行令牌序列
      this.executeTokens(tokens);
      
      return {
          points: [...this.points],
          trajectory: [...this.trajectory],
          finalState: { ...this.state },
          originalCode: code,  // 🔥 保存原始代码用于比较
          processedCode: processedCode  // 保存处理后的代码用于调试
      };
  }
  
  // 预处理代码：展开循环，处理条件语句
  preprocessCode(code) {
      let processed = code;
      
      // 首先处理C++风格的代码，提取main函数体
      processed = this.extractMainBody(processed);
      
      // 展开for循环
      processed = this.expandForLoops(processed);
      
      // 处理if语句（暂时简单处理，只执行条件为真的分支）
      processed = this.processIfStatements(processed);
      
      return processed;
  }
  
  // 提取main函数体中的代码
  extractMainBody(code) {
      logger.log('🔍 原始代码:', code);
      
      // 移除注释和多余空白
      let cleaned = code.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
      
      // 查找main函数体
      const mainMatch = cleaned.match(/int\s+main\s*\([^)]*\)\s*\{([\s\S]*)\}/);
      if (mainMatch) {
          let mainBody = mainMatch[1];
          logger.log('✅ 提取到main函数体:', mainBody);
          
          // 移除return语句
          mainBody = mainBody.replace(/return\s+\d+\s*;?\s*$/gm, '');
          
          return mainBody.trim();
      }
      
      // 如果没有找到main函数，返回原代码
      logger.log('⚠️ 未找到main函数，使用原代码');
      return code;
  }
  
  // 展开for循环
  expandForLoops(code) {
      logger.log('🔄 展开for循环，输入代码:', code);
      
      // 支持多种for循环格式，修复正则表达式
      const patterns = [
          // C++风格带花括号: for(int i=0;i<7;i++){ ... }
          /for\s*\(\s*int\s+(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<\s*(\d+)\s*;\s*\1\+\+\s*\)\s*\{([^}]*)\}/g,
          // C++风格带花括号: for(int i=0;i<=7;i++){ ... }
          /for\s*\(\s*int\s+(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<=\s*(\d+)\s*;\s*\1\+\+\s*\)\s*\{([^}]*)\}/g,
          // 简化风格带花括号: for(i=0;i<7;i++){ ... }
          /for\s*\(\s*(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<\s*(\d+)\s*;\s*\1\+\+\s*\)\s*\{([^}]*)\}/g,
          // 简化风格带花括号: for(i=0;i<=7;i++){ ... }
          /for\s*\(\s*(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<=\s*(\d+)\s*;\s*\1\+\+\s*\)\s*\{([^}]*)\}/g,
          // C++风格无花括号: for(int i=0;i<7;i++) statement;
          /for\s*\(\s*int\s+(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<\s*(\d+)\s*;\s*\1\+\+\s*\)\s*([^{;]+;)/g,
          // C++风格无花括号: for(int i=0;i<=7;i++) statement;
          /for\s*\(\s*int\s+(\w+)\s*=\s*(\d+)\s*;\s*\1\s*<=\s*(\d+)\s*;\s*\1\+\+\s*\)\s*([^{;]+;)/g
      ];
      
      let processed = code;
      
      for (const pattern of patterns) {
          processed = processed.replace(pattern, (match, varName, start, end, body) => {
              logger.log('🎯 匹配到for循环:', { 
                  match: match.trim(), 
                  varName, 
                  start, 
                  end, 
                  body: body.trim() 
              });
              
              let expanded = '';
              const startNum = parseInt(start);
              const endNum = parseInt(end);
              
              // 根据比较符号确定循环次数
              const isLessThan = match.includes('<') && !match.includes('<=');
              const actualEnd = isLessThan ? endNum - 1 : endNum;
              
              logger.log('🔢 循环范围:', { startNum, endNum, actualEnd, isLessThan });
              
              for (let i = startNum; i <= actualEnd; i++) {
                  // 替换循环变量
                  let expandedBody = body.replace(new RegExp('\\b' + varName + '\\b', 'g'), i.toString());
                  // 确保每个语句都有分号结尾
                  if (expandedBody.trim() && !expandedBody.trim().endsWith(';')) {
                      expandedBody = expandedBody.trim() + ';';
                  }
                  expanded += expandedBody + '\n';
              }
              
              logger.log('✅ 展开结果:', expanded.trim());
              return expanded.trim();
          });
      }
      
      logger.log('🔄 for循环展开完成:', processed);
      return processed;
  }
  
  // 处理if语句（简化版，只处理简单条件）
  processIfStatements(code) {
      const ifRegex = /if\s*\(\s*([^)]+)\s*\)\s*\{([^}]+)\}/g;
      
      return code.replace(ifRegex, (match, condition, body) => {
          // 简单评估条件（实际使用中需要更安全的评估）
          try {
              // 这里简化处理，假设条件为真
              // 实际应用中应该使用安全的表达式求值
              const isTrue = this.evaluateCondition(condition);
              return isTrue ? body : '';
          } catch (e) {
              return ''; // 如果条件评估失败，跳过
          }
      });
  }
  
  // 简单条件评估
  evaluateCondition(condition) {
      // 移除空格
      const cleanCondition = condition.replace(/\s/g, '');
      
      // 简单比较表达式
      const comparisons = ['==', '!=', '<=', '>=', '<', '>'];
      for (const op of comparisons) {
          if (cleanCondition.includes(op)) {
              const [left, right] = cleanCondition.split(op);
              const leftVal = this.parseValue(left);
              const rightVal = this.parseValue(right);
              
              switch (op) {
                  case '==': return leftVal === rightVal;
                  case '!=': return leftVal !== rightVal;
                  case '<=': return leftVal <= rightVal;
                  case '>=': return leftVal >= rightVal;
                  case '<': return leftVal < rightVal;
                  case '>': return leftVal > rightVal;
              }
          }
      }
      
      // 默认返回true（简化处理）
      return true;
  }
  
  parseValue(str) {
      if (!isNaN(str)) return parseFloat(str);
      if (str === 'true') return true;
      if (str === 'false') return false;
      return str;
  }
  
  // 代码令牌化
  tokenize(code) {
      const tokens = [];
      // 先按行分割，再按分号分割，保持代码结构
      const lines = code.split(/\r?\n/);
      
      for (const line of lines) {
          const cleanLine = line.trim();
          if (!cleanLine) continue;
          
          // 按分号分割每行，处理多个语句在一行的情况
          const statements = cleanLine.split(';').filter(stmt => stmt.trim());
          
          for (const statement of statements) {
              const cleanStatement = statement.trim();
              if (!cleanStatement) continue;
              
              logger.log('🔍 处理语句:', cleanStatement);
              
              // 处理链式调用，如 p.fd(100).rt(60) 或 pen.fd(100).rt(90)
              if (cleanStatement.includes('.') && cleanStatement.match(/\w+\.\w+\([^)]*\)/)) {
                  logger.log('🔗 检测到链式调用:', cleanStatement);
                  const chainTokens = this.parseChainedCalls(cleanStatement);
                  tokens.push(...chainTokens);
                  continue;
              }
              
              // 匹配单个命令和参数
              const commandMatch = cleanStatement.match(/^(\w+)\(([^)]*)\)$/);
              if (commandMatch) {
                  const [, command, args] = commandMatch;
                  tokens.push({
                      type: 'command',
                      command: command.toLowerCase(),
                      args: this.parseArgs(args),
                      original: cleanStatement
                  });
                  logger.log('📝 添加命令token:', command.toLowerCase());
              } else {
                  // 处理单个方法调用如 pen.up()
                  const propMatch = cleanStatement.match(/^(\w+)\.(\w+)\(([^)]*)\)$/);
                  if (propMatch) {
                      const [, obj, method, args] = propMatch;
                      tokens.push({
                          type: 'method',
                          object: obj,
                          method: method.toLowerCase(),
                          args: this.parseArgs(args),
                          original: cleanStatement
                      });
                      logger.log('📝 添加方法token:', obj + '.' + method.toLowerCase());
                  } else {
                      // 处理其他语法（如变量赋值等）
                      tokens.push({
                          type: 'other',
                          content: cleanStatement,
                          original: cleanStatement
                      });
                      logger.log('📝 添加其他token:', cleanStatement);
                  }
              }
          }
      }
      
      logger.log('📋 总共生成tokens:', tokens.length);
      return tokens;
  }
  
  // 解析链式调用，如 pen.fd(100).rt(90) 或 p.fd(100).rt(60)
  parseChainedCalls(line) {
      const tokens = [];
      logger.log('🔗 解析链式调用:', line);
      
      // 先找到起始对象
      const startMatch = line.match(/^(\w+)\./);
      if (!startMatch) {
          logger.log('❌ 未找到起始对象');
          return tokens;
      }
      
      const objectName = startMatch[1];
      logger.log('🎯 链式调用对象:', objectName);
      
      // 匹配所有的方法调用 .method(args)
      const methodPattern = /\.(\w+)\(([^)]*)\)/g;
      let match;
      let matchCount = 0;
      
      // 重置正则表达式的lastIndex
      methodPattern.lastIndex = 0;
      
      while ((match = methodPattern.exec(line)) !== null) {
          const [fullMatch, method, args] = match;
          matchCount++;
          
          logger.log(`🔍 解析到第${matchCount}个方法调用:`, {
              fullMatch,
              method,
              args,
              object: objectName
          });
          
          tokens.push({
              type: 'method',
              object: objectName,
              method: method.toLowerCase(),
              args: this.parseArgs(args),
              original: `${objectName}${fullMatch}`
          });
          
          logger.log('✅ 添加方法token:', {
              object: objectName,
              method: method.toLowerCase(),
              args: this.parseArgs(args)
          });
      }
      
      logger.log(`🔗 链式调用解析完成，共解析到${matchCount}个方法调用`);
      return tokens;
  }
  
  // 解析参数
  parseArgs(argsStr) {
      if (!argsStr.trim()) return [];
      return argsStr.split(',').map(arg => {
          const trimmed = arg.trim();
          // 尝试解析为数字
          if (!isNaN(trimmed)) return parseFloat(trimmed);
          // 处理字符串（移除引号）
          if ((trimmed.startsWith('"') && trimmed.endsWith('"')) || 
              (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
              return trimmed.slice(1, -1);
          }
          return trimmed;
      });
  }
  
  // 执行令牌序列
  executeTokens(tokens) {
      for (const token of tokens) {
          try {
              if (token.type === 'command') {
                  this.executeCommand(token.command, token.args);
              } else if (token.type === 'method') {
                  this.executeMethod(token.object, token.method, token.args);
              }
              // 忽略其他类型的令牌
          } catch (error) {
              logger.warn(`执行命令失败: ${token.original}`, error);
          }
      }
  }
  
  // 执行命令
  executeCommand(command, args) {
      switch (command) {
          case 'fd':
              this.forward(args[0] || 0);
              break;
          case 'bk':
              this.forward(-(args[0] || 0));
              break;
          case 'rt':
              this.turn(args[0] || 0);
              break;
          case 'lt':
              this.turn(-(args[0] || 0));
              break;
          case 'moveto':
              this.moveTo(args[0] || 0, args[1] || 0);
              break;
          case 'lineto':
              this.lineTo(args[0] || 0, args[1] || 0);
              break;
          case 'cls':
              this.clearScreen();
              break;
          case 'wait':
              // 等待命令，不影响轨迹
              break;
          default:
              // 其他命令可能影响状态但不产生轨迹点
              this.updateState(command, args);
      }
  }
  
  // 执行方法
  executeMethod(object, method, args) {
      logger.log('🎯 执行方法:', { object, method, args });
      
      // 支持 pen 和 p 两种对象名（p 是 pen 的简写）
      if (object === 'pen' || object === 'p') {
          switch (method) {
              case 'up':
                  this.state.penDown = false;
                  logger.log('✏️ 抬笔');
                  break;
              case 'down':
                  this.state.penDown = true;
                  logger.log('✏️ 落笔');
                  break;
              case 'size':
                  this.state.size = args[0] || 1;
                  logger.log('📏 设置笔粗:', this.state.size);
                  break;
              case 'c':
                  this.state.color = args[0] || 'black';
                  logger.log('🎨 设置颜色:', this.state.color);
                  break;
              case 'fd':
                  this.forward(args[0] || 0);
                  logger.log('⬆️ 前进:', args[0] || 0);
                  break;
              case 'bk':
                  this.forward(-(args[0] || 0));
                  logger.log('⬇️ 后退:', args[0] || 0);
                  break;
              case 'rt':
                  this.turn(args[0] || 0);
                  logger.log('↻ 右转:', args[0] || 0);
                  break;
              case 'lt':
                  this.turn(-(args[0] || 0));
                  logger.log('↺ 左转:', args[0] || 0);
                  break;
              case 'cls':
                  this.clearScreen();
                  logger.log('🧹 清屏');
                  break;
              case 'o':
                  // o方法：绘制圆形
                  this.drawCircle(args[0] || 50, false);
                  logger.log('⭕ 绘制圆形，半径:', args[0] || 50);
                  break;
              case 'oo':
                  // oo方法：绘制实心圆
                  this.drawCircle(args[0] || 50, true);
                  logger.log('🔵 绘制实心圆，半径:', args[0] || 50);
                  break;
              case 'e':
                  // e方法：绘制椭圆
                  this.drawEllipse(args[0] || 50, args[1] || 30, false);
                  logger.log('⭕ 绘制椭圆，宽:', args[0] || 50, '高:', args[1] || 30);
                  break;
              case 'ee':
                  // ee方法：绘制实心椭圆
                  this.drawEllipse(args[0] || 50, args[1] || 30, true);
                  logger.log('🔵 绘制实心椭圆，宽:', args[0] || 50, '高:', args[1] || 30);
                  break;
              case 'r': {
                  // r方法：绘制长方形/正方形
                  const width = args[0] || 50;
                  const height = args[1] || 30;
                  this.drawRectangle(width, height, false);
                  const shapeType = width === height ? '正方形' : '长方形';
                  logger.log(`⬜ 绘制${shapeType}，宽: ${width}, 高: ${height}`);
                  break;
              }
              case 'rr': {
                  // rr方法：绘制实心长方形/正方形
                  const filledWidth = args[0] || 50;
                  const filledHeight = args[1] || 30;
                  this.drawRectangle(filledWidth, filledHeight, true);
                  const filledShapeType = filledWidth === filledHeight ? '实心正方形' : '实心长方形';
                  logger.log(`⬛ 绘制${filledShapeType}，宽: ${filledWidth}, 高: ${filledHeight}`);
                  break;
              }
              default:
                  logger.log('❓ 未知pen方法:', method);
          }
      }
  }
  
  // 更新状态
  updateState(command, args) {
      switch (command) {
          case 'speed':
              this.state.speed = args[0] || 1;
              break;
          case 'show':
              this.state.visible = true;
              break;
          case 'hide':
              this.state.visible = false;
              break;
          case 'setprecision':
              this.state.precision = args[0] || 2;
              break;
      }
  }
  
  // 前进命令
  forward(distance) {
      if (!this.state.visible) return;
      
      const rad = this.state.angle * Math.PI / 180;
      const dx = distance * Math.cos(rad);
      const dy = distance * Math.sin(rad);
      
      const newX = this.state.x + dx;
      const newY = this.state.y + dy;
      
      if (this.state.penDown) {
          this.trajectory.push({
              from: { x: this.state.x, y: this.state.y },
              to: { x: newX, y: newY },
              color: this.state.color,
              size: this.state.size
          });
          
          this.points.push({ x: newX, y: newY });
      }
      
      this.state.x = newX;
      this.state.y = newY;
  }
  
  // 转向命令
  turn(angle) {
      this.state.angle = (this.state.angle + angle) % 360;
  }
  
  // 移动到指定位置
  moveTo(x, y) {
      this.state.x = x;
      this.state.y = y;
  }
  
  // 画线到指定位置
  lineTo(x, y) {
      if (this.state.penDown && this.state.visible) {
          this.trajectory.push({
              from: { x: this.state.x, y: this.state.y },
              to: { x, y },
              color: this.state.color,
              size: this.state.size
          });
          
          this.points.push({ x, y });
      }
      
      this.state.x = x;
      this.state.y = y;
  }
  
  // 清屏
  clearScreen() {
      this.points = [];
      this.trajectory = [];
      this.state.x = 0;
      this.state.y = 0;
      this.state.angle = 0;
  }
  
  // 绘制圆形
  drawCircle(radius, filled = false) {
      const centerX = this.state.x;
      const centerY = this.state.y;
      const numPoints = Math.max(16, Math.floor(radius / 3)); // 根据半径调整点数
      
      for (let i = 0; i <= numPoints; i++) {
          const angle = (i / numPoints) * 2 * Math.PI;
          const x = centerX + radius * Math.cos(angle);
          const y = centerY + radius * Math.sin(angle);
          
          if (this.state.penDown) {
              this.points.push({ 
                  x, 
                  y, 
                  shapeType: filled ? 'filled_circle' : 'circle',
                  radius: radius
              });
              this.trajectory.push({
                  x: x,
                  y: y,
                  penDown: true,
                  color: this.state.color,
                  size: this.state.size,
                  shapeType: filled ? 'filled_circle' : 'circle'
              });
          }
      }
  }
  
  // 绘制椭圆
  drawEllipse(width, height, filled = false) {
      const centerX = this.state.x;
      const centerY = this.state.y;
      const radiusX = width / 2;
      const radiusY = height / 2;
      const numPoints = Math.max(16, Math.floor((width + height) / 6));
      
      for (let i = 0; i <= numPoints; i++) {
          const angle = (i / numPoints) * 2 * Math.PI;
          const x = centerX + radiusX * Math.cos(angle);
          const y = centerY + radiusY * Math.sin(angle);
          
          if (this.state.penDown) {
              this.points.push({ 
                  x, 
                  y, 
                  shapeType: filled ? 'filled_ellipse' : 'ellipse',
                  width: width,
                  height: height
              });
              this.trajectory.push({
                  x: x,
                  y: y,
                  penDown: true,
                  color: this.state.color,
                  size: this.state.size,
                  shapeType: filled ? 'filled_ellipse' : 'ellipse'
              });
          }
      }
  }
  
  // 绘制长方形
  drawRectangle(width, height, filled = false) {
      const startX = this.state.x;
      const startY = this.state.y;
      
      // 绘制矩形的四条边
      const corners = [
          { x: startX, y: startY },
          { x: startX + width, y: startY },
          { x: startX + width, y: startY + height },
          { x: startX, y: startY + height },
          { x: startX, y: startY } // 回到起点闭合
      ];
      
      for (const corner of corners) {
          if (this.state.penDown) {
              // 根据宽高比例确定形状类型
              const isSquare = width === height;
              const baseShapeType = isSquare ? 'square' : 'rectangle';
              const shapeType = filled ? `filled_${baseShapeType}` : baseShapeType;
              
              this.points.push({ 
                  x: corner.x, 
                  y: corner.y,
                  shapeType: shapeType,
                  width: width,
                  height: height
              });
              this.trajectory.push({
                  x: corner.x,
                  y: corner.y,
                  penDown: true,
                  color: this.state.color,
                  size: this.state.size,
                  shapeType: shapeType
              });
          }
      }
      
      // 更新当前位置到矩形起点
      this.state.x = startX;
      this.state.y = startY;
  }
  
  // 重置状态
  resetState() {
      this.state = {
          x: 0,
          y: 0,
          angle: 0,
          penDown: true,
          color: 'black',
          size: 1,
          speed: 1,
          visible: true,
          precision: 2
      };
      this.trajectory = [];
      this.points = [];
  }
  
  // 比较两个轨迹
  compareTrajectories(userTraj, answerTraj, options) {
      const userPoints = userTraj.points;
      const answerPoints = answerTraj.points;
      const isRegular = options.isRegular || 0;
      
      logger.log('🔍 轨迹比较 - 用户点数:', userPoints.length, '答案点数:', answerPoints.length);
      logger.log('🔍 判题模式 isRegular:', isRegular, isRegular === 1 ? '(严格模式-指令顺序不敏感)' : '(宽松模式-原有逻辑)');
      logger.log('🔍 用户轨迹详情:', userTraj);
      logger.log('🔍 答案轨迹详情:', answerTraj);
      
      // 如果两个轨迹都为空，这通常意味着代码解析失败，不应该判为正确
      if (userPoints.length === 0 && answerPoints.length === 0) {
          logger.log('⚠️ 两个轨迹都为空，可能是代码解析失败');
          return { isValid: false, similarity: 0, details: { reason: 'Both trajectories are empty - possible parsing failure' } };
      }
      
      // 🔥 修改：如果其中一个轨迹为空，先进行指令顺序不敏感比较
      if (userPoints.length === 0 || answerPoints.length === 0) {
          logger.log('⚠️ 其中一个轨迹为空，尝试指令顺序不敏感比较');
          // 先进行指令顺序不敏感比较
          const orderInsensitiveResult = this.compareTrajectoriesOrderInsensitive(userTraj, answerTraj, options);
          if (orderInsensitiveResult.isValid) {
              logger.log('✅ 指令顺序不敏感比较通过，认为代码等价');
              return orderInsensitiveResult;
          }
          logger.log('❌ 指令顺序不敏感比较也失败');
          return { isValid: false, similarity: 0, details: { reason: 'One trajectory is empty and order-insensitive comparison failed' } };
      }
      
      // 🔥 修改：如果代码完全相同，直接返回高相似度（但先进行指令顺序不敏感比较）
      if (userTraj.originalCode && answerTraj.originalCode) {
          const userCode = userTraj.originalCode.trim().replace(/\s+/g, ' ');
          const answerCode = answerTraj.originalCode.trim().replace(/\s+/g, ' ');
          if (userCode === answerCode) {
              logger.log('✅ 检测到完全相同的代码，返回高相似度');
              return { 
                  isValid: true, 
                  similarity: 0.95, 
                  details: { 
                      reason: 'Identical code detected',
                      pointSimilarity: 1.0,
                      pathSimilarity: 1.0,
                      bboxSimilarity: 1.0
                  } 
              };
          }
      }
      
      // 🔥 修改：如果isRegular=1，禁用trace比对，只使用形状比对
      if (isRegular === 1) {
          logger.log('🔧 isRegular=1，禁用trace比对，只使用形状比对');
          return this.compareTrajectoriesShapeOnly(userTraj, answerTraj, options);
      }
      
      // 🔥 新增：使用指令顺序不敏感的轨迹比较方法
      logger.log('🔧 使用指令顺序不敏感的轨迹比较方法');
      return this.compareTrajectoriesOrderInsensitive(userTraj, answerTraj, options);
  }
  
  // 比较点集（顺序无关）
  comparePointSets(pointsA, pointsB, tolerance) {
      logger.log('🔍 点集比较 - A点数:', pointsA.length, 'B点数:', pointsB.length);
      
      // 🔥 如果两个点集都为空，认为完全相似
      if (pointsA.length === 0 && pointsB.length === 0) {
          logger.log('✅ 两个点集都为空，返回完全相似');
          return 1.0;
      }
      
      // 🔥 如果其中一个为空，另一个不为空，返回0
      if (pointsA.length === 0 || pointsB.length === 0) {
          logger.log('❌ 其中一个点集为空，返回0相似度');
          return 0;
      }
      
      if (pointsA.length !== pointsB.length) {
          // 如果点数不同，计算基于重叠的相似度
          const maxPoints = Math.max(pointsA.length, pointsB.length);
          let matched = 0;
          
          for (const pointA of pointsA) {
              for (const pointB of pointsB) {
                  const distance = Math.sqrt(
                      Math.pow(pointA.x - pointB.x, 2) + 
                      Math.pow(pointA.y - pointB.y, 2)
                  );
                  if (distance <= tolerance) {
                      matched++;
                      break;
                  }
              }
          }
          
          const similarity = matched / maxPoints;
          logger.log('📊 不同点数相似度:', similarity, '(匹配:', matched, '/', maxPoints, ')');
          return similarity;
      }
      
      // 如果点数相同，计算平均距离相似度
      let totalDistance = 0;
      for (let i = 0; i < pointsA.length; i++) {
          const distance = Math.sqrt(
              Math.pow(pointsA[i].x - pointsB[i].x, 2) + 
              Math.pow(pointsA[i].y - pointsB[i].y, 2)
          );
          totalDistance += distance;
      }
      
      const avgDistance = totalDistance / pointsA.length;
      // 🔥 优化相似度计算，提高容错性
      const similarity = Math.max(0, 1 - avgDistance / (tolerance * 5)); // 降低分母，提高相似度
      logger.log('📊 相同点数相似度:', similarity, '(平均距离:', avgDistance.toFixed(2), ')');
      return similarity;
  }
  
  // 比较路径形状
  comparePathShapes(pointsA, pointsB) {
      // 简化：比较路径的总体走向
      if (pointsA.length < 2 || pointsB.length < 2) return 1; // 如果都是单点或空，认为相似
      
      // 计算路径的总长度和方向变化
      const featuresA = this.extractPathFeatures(pointsA);
      const featuresB = this.extractPathFeatures(pointsB);
      
      // 比较特征 - 防止除以0
      let lengthSimilarity = 1;
      const maxLength = Math.max(featuresA.totalLength, featuresB.totalLength);
      if (maxLength > 0) {
          lengthSimilarity = 1 - Math.abs(featuresA.totalLength - featuresB.totalLength) / maxLength;
      }
      
      let turnSimilarity = 1;
      if (featuresA.avgTurn !== 0 || featuresB.avgTurn !== 0) {
          turnSimilarity = 1 - Math.abs(featuresA.avgTurn - featuresB.avgTurn) / 180;
      }
      
      return (lengthSimilarity + turnSimilarity) / 2;
  }
  
  // 提取路径特征
  extractPathFeatures(points) {
      let totalLength = 0;
      let totalTurn = 0;
      let turnCount = 0;
      
      for (let i = 1; i < points.length; i++) {
          // 计算线段长度
          const dx = points[i].x - points[i-1].x;
          const dy = points[i].y - points[i-1].y;
          totalLength += Math.sqrt(dx * dx + dy * dy);
          
          // 计算转向角度（如果有前一个线段）
          if (i > 1) {
              const prevDx = points[i-1].x - points[i-2].x;
              const prevDy = points[i-1].y - points[i-2].y;
              const prevAngle = Math.atan2(prevDy, prevDx);
              const currAngle = Math.atan2(dy, dx);
              let turn = Math.abs(currAngle - prevAngle) * 180 / Math.PI;
              if (turn > 180) turn = 360 - turn;
              totalTurn += turn;
              turnCount++;
          }
      }
      
      return {
          totalLength,
          avgTurn: turnCount > 0 ? totalTurn / turnCount : 0
      };
  }
  
  // 比较边界框
  compareBoundingBoxes(pointsA, pointsB) {
      const bboxA = this.calculateBoundingBox(pointsA);
      const bboxB = this.calculateBoundingBox(pointsB);
      
      if (!bboxA || !bboxB) return 1; // 如果无法计算边界框，认为相似
      
      const areaA = bboxA.width * bboxA.height;
      const areaB = bboxB.width * bboxB.height;
      
      // 防止除以0 - 如果两个面积都为0（单点），认为相似
      let areaSimilarity = 1;
      const maxArea = Math.max(areaA, areaB);
      if (maxArea > 0) {
          areaSimilarity = 1 - Math.abs(areaA - areaB) / maxArea;
      }
      
      const centerDistance = Math.sqrt(
          Math.pow(bboxA.centerX - bboxB.centerX, 2) + 
          Math.pow(bboxA.centerY - bboxB.centerY, 2)
      );
      
      // 防止除以0 - 如果最大维度为0（单点），只看中心距离
      let centerSimilarity = 1;
      const maxDimension = Math.max(bboxA.width, bboxA.height, bboxB.width, bboxB.height);
      if (maxDimension > 0) {
          centerSimilarity = Math.max(0, 1 - centerDistance / maxDimension);
      } else {
          // 如果都是单点，看中心距离是否为0
          centerSimilarity = centerDistance === 0 ? 1 : 0;
      }
      
      return (areaSimilarity + centerSimilarity) / 2;
  }
  
  calculateBoundingBox(points) {
      if (points.length === 0) return null;
      
      let minX = Infinity, minY = Infinity;
      let maxX = -Infinity, maxY = -Infinity;
      
      for (const point of points) {
          minX = Math.min(minX, point.x);
          minY = Math.min(minY, point.y);
          maxX = Math.max(maxX, point.x);
          maxY = Math.max(maxY, point.y);
      }
      
      return {
          minX, minY, maxX, maxY,
          width: maxX - minX,
          height: maxY - minY,
          centerX: (minX + maxX) / 2,
          centerY: (minY + maxY) / 2
      };
  }
  
  // 🔥 新增：仅使用形状比对的轨迹比较方法（isRegular=1时使用）
  compareTrajectoriesShapeOnly(userTraj, answerTraj, options) {
      logger.log('🔧 开始仅形状比对（isRegular=1模式）');
      
      const userPoints = userTraj.points;
      const answerPoints = answerTraj.points;
      
      logger.log('🔍 形状比对 - 用户点数:', userPoints.length, '答案点数:', answerPoints.length);
      
      // 如果两个轨迹都为空，返回失败
      if (userPoints.length === 0 && answerPoints.length === 0) {
          logger.log('⚠️ 两个轨迹都为空');
          return { isValid: false, similarity: 0, details: { reason: 'Both trajectories are empty' } };
      }
      
      if (userPoints.length === 0 || answerPoints.length === 0) {
          logger.log('❌ 其中一个轨迹为空');
          return { isValid: false, similarity: 0, details: { reason: 'One trajectory is empty' } };
      }
      
      // 只进行形状相关的比较
      const shapeSimilarity = this.compareShapesOnly(userPoints, answerPoints, options);
      
      logger.log('📊 形状相似度:', shapeSimilarity);
      
      // 形状比对：相似度>=0.69认为形状相同，否则不同
      const isValid = shapeSimilarity >= 0.69;
      
      return {
          isValid,
          similarity: isValid ? 1.0 : 0.0, // 要么100%要么0%
          details: {
              shapeSimilarity,
              userPointCount: userPoints.length,
              answerPointCount: answerPoints.length,
              reason: isValid ? 'Shapes match (isRegular=1 mode)' : 'Shapes differ (isRegular=1 mode)'
          }
      };
  }
  
  // 仅进行形状比较的方法（完全避免trace比对）
  compareShapesOnly(pointsA, pointsB, options) {
      logger.log('🔍 开始纯形状比较（无trace比对）');
      
      // 方法1：边界框比较（只比较图形的外框）
      const bboxSimilarity = this.compareBoundingBoxes(pointsA, pointsB);
      
      // 方法2：点集分布比较（只比较点的分布特征）
      const distributionSimilarity = this.comparePointDistribution(pointsA, pointsB, options.tolerance);
      
      // 方法3：图形面积比较
      const areaSimilarity = this.compareAreas(pointsA, pointsB);
      
      // 方法4：图形中心位置比较
      const centerSimilarity = this.compareCenters(pointsA, pointsB);
      
      // 综合形状相似度（只使用纯几何特征）
      const overallSimilarity = (bboxSimilarity * 0.3 + distributionSimilarity * 0.3 + areaSimilarity * 0.2 + centerSimilarity * 0.2);
      
      logger.log('📊 纯形状比较详情:');
      logger.log('  - 边界框相似度:', bboxSimilarity);
      logger.log('  - 点集分布相似度:', distributionSimilarity);
      logger.log('  - 面积相似度:', areaSimilarity);
      logger.log('  - 中心位置相似度:', centerSimilarity);
      logger.log('  - 综合形状相似度:', overallSimilarity);
      
      return overallSimilarity;
  }
  
  // 比较点集分布（容忍位置差异）
  comparePointDistribution(pointsA, pointsB, tolerance) {
      if (pointsA.length === 0 || pointsB.length === 0) return 0;
      
      // 计算两个点集的中心
      const centerA = this.calculateCenter(pointsA);
      const centerB = this.calculateCenter(pointsB);
      
      // 计算中心距离
      const centerDistance = Math.sqrt(
          Math.pow(centerA.x - centerB.x, 2) + 
          Math.pow(centerA.y - centerB.y, 2)
      );
      
      // 计算点集的标准差（衡量点的分布）
      const stdA = this.calculateStandardDeviation(pointsA, centerA);
      const stdB = this.calculateStandardDeviation(pointsB, centerB);
      
      // 中心距离相似度
      const maxDimension = Math.max(stdA, stdB);
      const centerSimilarity = maxDimension > 0 ? 
          Math.max(0, 1 - centerDistance / (maxDimension * 2)) : 
          (centerDistance === 0 ? 1 : 0);
      
      // 分布形状相似度
      const distributionSimilarity = Math.max(0, 1 - Math.abs(stdA - stdB) / Math.max(stdA, stdB));
      
      return (centerSimilarity + distributionSimilarity) / 2;
  }
  
  // 计算点集中心
  calculateCenter(points) {
      if (points.length === 0) return { x: 0, y: 0 };
      
      const sumX = points.reduce((sum, p) => sum + p.x, 0);
      const sumY = points.reduce((sum, p) => sum + p.y, 0);
      
      return {
          x: sumX / points.length,
          y: sumY / points.length
      };
  }
  
  // 计算点集的标准差
  calculateStandardDeviation(points, center) {
      if (points.length === 0) return 0;
      
      const distances = points.map(p => 
          Math.sqrt(Math.pow(p.x - center.x, 2) + Math.pow(p.y - center.y, 2))
      );
      
      const meanDistance = distances.reduce((sum, d) => sum + d, 0) / distances.length;
      const variance = distances.reduce((sum, d) => sum + Math.pow(d - meanDistance, 2), 0) / distances.length;
      
      return Math.sqrt(variance);
  }
  
  // 🔥 新增：比较图形面积（纯几何特征）
  compareAreas(pointsA, pointsB) {
      if (pointsA.length === 0 || pointsB.length === 0) return 0;
      
      // 计算边界框面积
      const bboxA = this.calculateBoundingBox(pointsA);
      const bboxB = this.calculateBoundingBox(pointsB);
      
      if (!bboxA || !bboxB) return 1;
      
      const areaA = bboxA.width * bboxA.height;
      const areaB = bboxB.width * bboxB.height;
      
      // 防止除以0
      const maxArea = Math.max(areaA, areaB);
      if (maxArea === 0) return 1;
      
      const areaSimilarity = 1 - Math.abs(areaA - areaB) / maxArea;
      logger.log('📊 面积比较:', { areaA, areaB, similarity: areaSimilarity });
      
      return areaSimilarity;
  }
  
  // 🔥 新增：比较图形中心位置（纯几何特征）
  compareCenters(pointsA, pointsB) {
      if (pointsA.length === 0 || pointsB.length === 0) return 0;
      
      const centerA = this.calculateCenter(pointsA);
      const centerB = this.calculateCenter(pointsB);
      
      // 计算中心距离
      const centerDistance = Math.sqrt(
          Math.pow(centerA.x - centerB.x, 2) + 
          Math.pow(centerA.y - centerB.y, 2)
      );
      
      // 计算两个图形的最大尺寸作为参考
      const bboxA = this.calculateBoundingBox(pointsA);
      const bboxB = this.calculateBoundingBox(pointsB);
      
      if (!bboxA || !bboxB) return 1;
      
      const maxDimension = Math.max(bboxA.width, bboxA.height, bboxB.width, bboxB.height);
      
      // 如果最大尺寸为0（单点），只看中心距离是否为0
      if (maxDimension === 0) {
          return centerDistance === 0 ? 1 : 0;
      }
      
      // 中心距离相似度
      const centerSimilarity = Math.max(0, 1 - centerDistance / maxDimension);
      logger.log('📊 中心位置比较:', { centerA, centerB, distance: centerDistance, similarity: centerSimilarity });
      
      return centerSimilarity;
  }
  
  // 🔥 新增：指令顺序不敏感的轨迹比较方法
  compareTrajectoriesOrderInsensitive(userTraj, answerTraj, options) {
      logger.log('🔧 开始指令顺序不敏感的轨迹比较');
      
      // 提取用户和答案的指令序列
      const userCommands = this.extractCommandSequence(userTraj);
      const answerCommands = this.extractCommandSequence(answerTraj);
      
      logger.log('📋 用户指令序列:', userCommands);
      logger.log('📋 答案指令序列:', answerCommands);
      
      // 🔥 新增：定义需要忽略顺序的指令（.up(), .size(), .down(), .c()）
      const orderInsensitiveCommands = ['up', 'down', 'size', 'c'];
      
      // 🔥 新增：使用智能标准化指令序列，忽略指定指令的顺序
      const normalizedUserCommands = this.normalizeCommandSequenceSmartOrderInsensitive(userCommands, orderInsensitiveCommands);
      const normalizedAnswerCommands = this.normalizeCommandSequenceSmartOrderInsensitive(answerCommands, orderInsensitiveCommands);
      
      logger.log('📋 标准化后用户指令序列（忽略.up/.size/.down/.c顺序）:', normalizedUserCommands);
      logger.log('📋 标准化后答案指令序列（忽略.up/.size/.down/.c顺序）:', normalizedAnswerCommands);
      
      // 比较标准化后的指令序列
      const commandSimilarity = this.compareCommandSequencesOrderInsensitive(normalizedUserCommands, normalizedAnswerCommands);
      
      // 🔥 新增：如果指令相似度很高，直接认为代码等价（即使轨迹点数不同）
      if (commandSimilarity >= 0.9) {
          logger.log('✅ 指令相似度很高，认为代码等价');
          return {
              isValid: true,
              similarity: commandSimilarity,
              details: {
                  commandSimilarity,
                  pointSimilarity: 1.0, // 强制设为1.0
                  userCommandCount: userCommands.length,
                  answerCommandCount: answerCommands.length,
                  reason: 'High command similarity - codes considered equivalent'
              }
          };
      }
      
      // 仍然进行点集比较作为辅助验证
      const pointSimilarity = this.comparePointSets(userTraj.points, answerTraj.points, options.tolerance);
      
      // 综合相似度计算
      const overallSimilarity = (commandSimilarity * 0.8 + pointSimilarity * 0.2);
      
      logger.log('📊 指令顺序不敏感比较结果:');
      logger.log('  - 指令相似度:', commandSimilarity);
      logger.log('  - 点集相似度:', pointSimilarity);
      logger.log('  - 综合相似度:', overallSimilarity);
      
      const isValid = overallSimilarity >= 0.69;
      
      return {
          isValid,
          similarity: overallSimilarity,
          details: {
              commandSimilarity,
              pointSimilarity,
              userCommandCount: userCommands.length,
              answerCommandCount: answerCommands.length,
              reason: isValid ? 'Order-insensitive trajectories match' : 'Order-insensitive trajectories differ significantly'
          }
      };
  }
  
  // 从轨迹中提取指令序列
  extractCommandSequence(trajectory) {
      const commands = [];
      
      // 从原始代码中提取指令（如果可用）
      if (trajectory.originalCode) {
          const code = trajectory.originalCode;
          
          // 🔥 改进：支持多种指令格式
          // 1. 链式调用：p.fd(100).rt(90)
          // 2. 分离调用：p.fd(100); p.rt(90);
          // 3. 直接调用：fd(100); rt(90);
          
          // 先处理链式调用
          const chainedPattern = /(\w+)\.(\w+)\(([^)]*)\)(?:\.(\w+)\(([^)]*)\))*/g;
          let chainedMatch;
          
          while ((chainedMatch = chainedPattern.exec(code)) !== null) {
              const object = chainedMatch[1];
              const firstMethod = chainedMatch[2];
              const firstArgs = chainedMatch[3];
              
              // 添加第一个方法调用
              commands.push({
                  cmd: firstMethod.toLowerCase(),
                  args: this.parseArgs(firstArgs),
                  object: object
              });
              
              // 处理链式调用的后续方法
              const fullMatch = chainedMatch[0];
              const methodPattern = /\.(\w+)\(([^)]*)\)/g;
              let methodMatch;
              
              while ((methodMatch = methodPattern.exec(fullMatch)) !== null) {
                  if (methodMatch[1] !== firstMethod) { // 避免重复添加第一个方法
                      commands.push({
                          cmd: methodMatch[1].toLowerCase(),
                          args: this.parseArgs(methodMatch[2]),
                          object: object
                      });
                  }
              }
          }
          
          // 处理分离的指令调用
          const separatedPattern = /(\w+)\.(\w+)\(([^)]*)\)/g;
          let separatedMatch;
          
          while ((separatedMatch = separatedPattern.exec(code)) !== null) {
              const object = separatedMatch[1];
              const method = separatedMatch[2];
              const args = separatedMatch[3];
              
              // 检查是否已经添加过（避免重复）
              const alreadyAdded = commands.some(cmd => 
                  cmd.cmd === method.toLowerCase() && 
                  JSON.stringify(cmd.args) === JSON.stringify(this.parseArgs(args)) &&
                  cmd.object === object
              );
              
              if (!alreadyAdded) {
                  commands.push({
                      cmd: method.toLowerCase(),
                      args: this.parseArgs(args),
                      object: object
                  });
              }
          }
          
          // 处理直接调用（没有对象前缀）
          const directPattern = /^(\w+)\(([^)]*)\)/gm;
          let directMatch;
          
          while ((directMatch = directPattern.exec(code)) !== null) {
              const method = directMatch[1];
              const args = directMatch[2];
              
              // 检查是否已经添加过
              const alreadyAdded = commands.some(cmd => 
                  cmd.cmd === method.toLowerCase() && 
                  JSON.stringify(cmd.args) === JSON.stringify(this.parseArgs(args))
              );
              
              if (!alreadyAdded) {
                  commands.push({
                      cmd: method.toLowerCase(),
                      args: this.parseArgs(args)
                  });
              }
          }
      }
      
      logger.log('🔍 提取到的指令序列:', commands);
      return commands;
  }
  
  // 🔥 新增：指令顺序不敏感的标准化方法
  normalizeCommandSequenceOrderInsensitive(commands, orderInsensitiveCommands) {
      logger.log('🔧 开始指令顺序不敏感标准化:', commands);
      
      const normalized = [];
      const orderInsensitiveGroup = [];
      let i = 0;
      
      while (i < commands.length) {
          const current = commands[i];
          
          // 检查是否是需要忽略顺序的指令
          if (orderInsensitiveCommands.includes(current.cmd)) {
              // 收集所有需要忽略顺序的指令
              orderInsensitiveGroup.push(current);
              i++;
          } else {
              // 如果遇到其他指令，先处理之前收集的忽略顺序指令组
              if (orderInsensitiveGroup.length > 0) {
                  // 将忽略顺序的指令按类型分组并排序
                  const groupedCommands = this.groupAndSortOrderInsensitiveCommands(orderInsensitiveGroup);
                  normalized.push(...groupedCommands);
                  orderInsensitiveGroup.length = 0; // 清空数组
              }
              
              // 添加当前指令
              normalized.push(current);
              i++;
          }
      }
      
      // 处理最后剩余的忽略顺序指令组
      if (orderInsensitiveGroup.length > 0) {
          const groupedCommands = this.groupAndSortOrderInsensitiveCommands(orderInsensitiveGroup);
          normalized.push(...groupedCommands);
      }
      
      logger.log('🔧 指令顺序不敏感标准化后的指令序列:', normalized);
      return normalized;
  }
  
  // 🔥 新增：智能指令顺序不敏感标准化方法（考虑笔状态）
  normalizeCommandSequenceSmartOrderInsensitive(commands, orderInsensitiveCommands) {
      logger.log('🔧 开始智能指令顺序不敏感标准化:', commands);
      
      // 分离影响笔状态的指令和其他指令
      const penStateCommands = ['up', 'down'];
      const otherOrderInsensitiveCommands = ['size', 'c'];
      
      const normalized = [];
      const orderInsensitiveGroup = [];
      let i = 0;
      
      while (i < commands.length) {
          const current = commands[i];
          
          if (orderInsensitiveCommands.includes(current.cmd)) {
              // 收集所有忽略顺序的指令
              orderInsensitiveGroup.push(current);
              i++;
          } else {
              // 如果遇到其他指令，先处理之前收集的忽略顺序指令组
              if (orderInsensitiveGroup.length > 0) {
                  // 智能排序：优先处理笔状态指令，然后处理其他指令
                  const smartGroupedCommands = this.smartGroupOrderInsensitiveCommands(orderInsensitiveGroup);
                  normalized.push(...smartGroupedCommands);
                  orderInsensitiveGroup.length = 0;
              }
              
              // 添加当前指令
              normalized.push(current);
              i++;
          }
      }
      
      // 处理最后剩余的忽略顺序指令组
      if (orderInsensitiveGroup.length > 0) {
          const smartGroupedCommands = this.smartGroupOrderInsensitiveCommands(orderInsensitiveGroup);
          normalized.push(...smartGroupedCommands);
      }
      
      logger.log('🔧 智能指令顺序不敏感标准化后的指令序列:', normalized);
      return normalized;
  }
  
  // 🔥 新增：智能分组忽略顺序的指令
  smartGroupOrderInsensitiveCommands(orderInsensitiveGroup) {
      const result = [];
      
      // 分离不同类型的指令
      const downCommands = orderInsensitiveGroup.filter(cmd => cmd.cmd === 'down');
      const upCommands = orderInsensitiveGroup.filter(cmd => cmd.cmd === 'up');
      const sizeCommands = orderInsensitiveGroup.filter(cmd => cmd.cmd === 'size');
      const cCommands = orderInsensitiveGroup.filter(cmd => cmd.cmd === 'c');
      
      // 智能排序：优先处理笔状态指令，然后处理其他指令
      // 1. 先添加down指令
      result.push(...downCommands);
      
      // 2. 再添加size和c指令（按类型排序）
      sizeCommands.sort((a, b) => JSON.stringify(a.args).localeCompare(JSON.stringify(b.args)));
      cCommands.sort((a, b) => JSON.stringify(a.args).localeCompare(JSON.stringify(b.args)));
      result.push(...sizeCommands);
      result.push(...cCommands);
      
      // 3. 最后添加up指令
      result.push(...upCommands);
      
      return result;
  }
  
  // 🔥 新增：分组并排序忽略顺序的指令
  groupAndSortOrderInsensitiveCommands(commands) {
      // 按指令类型分组
      const groups = {
          up: [],
          down: [],
          size: [],
          c: []
      };
      
      // 将指令按类型分组
      for (const cmd of commands) {
          if (groups[cmd.cmd]) {
              groups[cmd.cmd].push(cmd);
          }
      }
      
      // 按固定顺序输出指令（up, down, size, c）
      const result = [];
      const order = ['up', 'down', 'size', 'c'];
      
      for (const cmdType of order) {
          if (groups[cmdType].length > 0) {
              // 对于相同类型的指令，按参数排序
              groups[cmdType].sort((a, b) => {
                  const argsA = JSON.stringify(a.args);
                  const argsB = JSON.stringify(b.args);
                  return argsA.localeCompare(argsB);
              });
              result.push(...groups[cmdType]);
          }
      }
      
      logger.log('🔧 分组排序后的忽略顺序指令:', result);
      return result;
  }
  
  // 🔥 新增：指令顺序不敏感的比较方法
  compareCommandSequencesOrderInsensitive(userCommands, answerCommands) {
      logger.log('🔍 比较指令顺序不敏感的指令序列');
      
      // 将指令序列转换为可比较的字符串
      const userStr = this.commandSequenceToStringOrderInsensitive(userCommands);
      const answerStr = this.commandSequenceToStringOrderInsensitive(answerCommands);
      
      logger.log('📝 用户指令字符串（顺序不敏感）:', userStr);
      logger.log('📝 答案指令字符串（顺序不敏感）:', answerStr);
      
      // 如果字符串完全相同，返回高相似度
      if (userStr === answerStr) {
          logger.log('✅ 指令序列完全相同（忽略.up/.size/.down/.c顺序）');
          return 1.0;
      }
      
      // 计算指令集合的相似度
      const userCmdSet = new Set(userCommands.map(cmd => this.commandToStringOrderInsensitive(cmd)));
      const answerCmdSet = new Set(answerCommands.map(cmd => this.commandToStringOrderInsensitive(cmd)));
      
      logger.log('📋 用户指令集合（顺序不敏感）:', [...userCmdSet]);
      logger.log('📋 答案指令集合（顺序不敏感）:', [...answerCmdSet]);
      
      const intersection = new Set([...userCmdSet].filter(cmd => answerCmdSet.has(cmd)));
      const union = new Set([...userCmdSet, ...answerCmdSet]);
      
      const jaccardSimilarity = intersection.size / union.size;
      
      logger.log('📊 Jaccard相似度（顺序不敏感）:', jaccardSimilarity);
      logger.log('📊 交集大小:', intersection.size);
      logger.log('📊 并集大小:', union.size);
      
      return jaccardSimilarity;
  }
  
  // 🔥 新增：将指令序列转换为字符串（顺序不敏感）
  commandSequenceToStringOrderInsensitive(commands) {
      return commands.map(cmd => this.commandToStringOrderInsensitive(cmd)).join('|');
  }
  
  // 🔥 新增：将单个指令转换为字符串（顺序不敏感）
  commandToStringOrderInsensitive(command) {
      return `${command.cmd}(${command.args.join(',')})`;
  }

  // 🔥 改进的标准化指令序列方法
  normalizeCommandSequenceImproved(commands, turnCommands, otherCommands) {
      logger.log('🔧 开始标准化指令序列:', commands);
      
      const normalized = [];
      let i = 0;
      
      while (i < commands.length) {
          const current = commands[i];
          
          // 检查是否是转弯指令
          if (turnCommands.includes(current.cmd)) {
              // 查找后续的其他指令
              let j = i + 1;
              const followingCommands = [];
              
              while (j < commands.length && otherCommands.includes(commands[j].cmd)) {
                  followingCommands.push(commands[j]);
                  j++;
              }
              
              if (followingCommands.length > 0) {
                  // 将转弯指令和其他指令组合为一个操作组
                  normalized.push({
                      type: 'operation_group',
                      turn: current,
                      other: followingCommands,
                      signature: this.createOperationSignature(current, followingCommands)
                  });
                  i = j;
              } else {
                  // 单独的转弯指令
                  normalized.push(current);
                  i++;
              }
          } else if (otherCommands.includes(current.cmd)) {
              // 检查是否是其他指令，查找后续的转弯指令
              let j = i + 1;
              const followingTurns = [];
              
              while (j < commands.length && turnCommands.includes(commands[j].cmd)) {
                  followingTurns.push(commands[j]);
                  j++;
              }
              
              if (followingTurns.length > 0) {
                  // 将其他指令和转弯指令组合为一个操作组
                  normalized.push({
                      type: 'operation_group',
                      other: [current],
                      turn: followingTurns[0], // 取第一个转弯指令
                      signature: this.createOperationSignature(followingTurns[0], [current])
                  });
                  i = j;
              } else {
                  // 单独的其他指令
                  normalized.push(current);
                  i++;
              }
          } else {
              // 其他类型的指令直接添加
              normalized.push(current);
              i++;
          }
      }
      
      logger.log('🔧 标准化后的指令序列:', normalized);
      return normalized;
  }
  
  // 创建操作组的签名，用于比较
  createOperationSignature(turnCommand, otherCommands) {
      // 将转弯指令和其他指令的参数组合成一个签名
      const turnSig = `${turnCommand.cmd}(${turnCommand.args.join(',')})`;
      const otherSig = otherCommands.map(cmd => `${cmd.cmd}(${cmd.args.join(',')})`).sort().join(',');
      return `${turnSig}+${otherSig}`;
  }
  
  // 🔥 改进的比较标准化指令序列方法
  compareCommandSequencesImproved(userCommands, answerCommands) {
      logger.log('🔍 比较标准化指令序列');
      
      // 将操作组转换为可比较的字符串
      const userStr = this.commandSequenceToStringImproved(userCommands);
      const answerStr = this.commandSequenceToStringImproved(answerCommands);
      
      logger.log('📝 用户指令字符串:', userStr);
      logger.log('📝 答案指令字符串:', answerStr);
      
      // 如果字符串完全相同，返回高相似度
      if (userStr === answerStr) {
          logger.log('✅ 指令序列完全相同');
          return 1.0;
      }
      
      // 计算指令集合的相似度
      const userCmdSet = new Set(userCommands.map(cmd => this.commandToStringImproved(cmd)));
      const answerCmdSet = new Set(answerCommands.map(cmd => this.commandToStringImproved(cmd)));
      
      logger.log('📋 用户指令集合:', [...userCmdSet]);
      logger.log('📋 答案指令集合:', [...answerCmdSet]);
      
      const intersection = new Set([...userCmdSet].filter(cmd => answerCmdSet.has(cmd)));
      const union = new Set([...userCmdSet, ...answerCmdSet]);
      
      const jaccardSimilarity = intersection.size / union.size;
      
      logger.log('📊 Jaccard相似度:', jaccardSimilarity);
      logger.log('📊 交集大小:', intersection.size);
      logger.log('📊 并集大小:', union.size);
      
      return jaccardSimilarity;
  }
  
  // 🔥 改进的将指令序列转换为字符串
  commandSequenceToStringImproved(commands) {
      return commands.map(cmd => this.commandToStringImproved(cmd)).join('|');
  }
  
  // 🔥 改进的将单个指令转换为字符串
  commandToStringImproved(command) {
      if (command.type === 'operation_group') {
          // 操作组：使用签名进行比较
          return command.signature;
      } else {
          return `${command.cmd}(${command.args.join(',')})`;
      }
  }
  
  // 保留原有方法以兼容性
  commandSequenceToString(commands) {
      return commands.map(cmd => this.commandToString(cmd)).join('|');
  }
  
  // 保留原有方法以兼容性
  commandToString(command) {
      if (command.type === 'operation_group') {
          // 操作组：将转弯和其他指令组合
          const turnStr = `${command.turn.cmd}(${command.turn.args.join(',')})`;
          const otherStr = command.other.map(cmd => `${cmd.cmd}(${cmd.args.join(',')})`).join(',');
          return `[${turnStr}+${otherStr}]`;
      } else {
          return `${command.cmd}(${command.args.join(',')})`;
      }
  }
}

// 测试用例（可以取消注释进行测试）
function testValidation() {
  const validator = new CodeTrajectoryValidator();
  
  // 测试用例：用户提到的问题代码
  const userCode = `int main(){
for(int i=0;i<7;i++){
  p.fd(100).rt(60);
}
return 0;
}`;
  
  const answerCode = `int main(){
for(int i=0;i<7;i++){
  p.fd(100).rt(60);
}
return 0;
}`;
  
  logger.log('🧪 开始测试修复后的代码...');
  const result = validator.validate(userCode, answerCode);
  logger.log('🎯 测试结果:', result);
  logger.log('📊 相似度:', result.similarity);
  logger.log('✅ 是否通过:', result.isValid);
  logger.log('📈 用户轨迹点数:', result.userPoints);
  logger.log('📈 答案轨迹点数:', result.answerPoints);
  
  return result;
}

// 🔥 新增：测试isRegular参数功能
function testIsRegularFeature() {
  const validator = new CodeTrajectoryValidator();
  
  // 测试用例：用户提供的具体案例
  const userCode = `int main(){
p.fd(100);
p.rt(90);
p.fd(100);
p.rt(90);
p.fd(100);
p.rt(90);
p.fd(100);
p.rt(90);
return 0;
}`;
  
  const answerCode = `int main(){
p.rt(90);
p.fd(100);
p.rt(90);
p.fd(100);
p.rt(90);
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  logger.log('🧪 开始测试isRegular功能...');
  logger.log('📋 用户代码（先前进再转弯）:', userCode);
  logger.log('📋 答案代码（先转弯再前进）:', answerCode);
  
  // 测试isRegular=0（宽松模式，使用原有逻辑）
  logger.log('📋 测试isRegular=0（宽松模式）:');
  const result0 = validator.validate(userCode, answerCode, { isRegular: 0 });
  logger.log('🎯 isRegular=0 结果:', result0);
  logger.log('📊 相似度:', result0.similarity);
  logger.log('✅ 是否通过:', result0.isValid);
  
  // 测试isRegular=1（严格模式，只使用形状比对）
  logger.log('📋 测试isRegular=1（严格模式-只使用形状比对）:');
  const result1 = validator.validate(userCode, answerCode, { isRegular: 1 });
  logger.log('🎯 isRegular=1 结果:', result1);
  logger.log('📊 相似度:', result1.similarity);
  logger.log('✅ 是否通过:', result1.isValid);
  logger.log('📝 详情:', result1.details);
  
  return { result0, result1 };
}

// 🔥 新增：测试.up/.size/.down/.c指令顺序不敏感功能
function testOrderInsensitiveCommands() {
  const validator = new CodeTrajectoryValidator();
  
  // 测试用例1：.up()和.size()顺序不同
  const userCode1 = `int main(){
p.up();
p.size(5);
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  const answerCode1 = `int main(){
p.size(5);
p.up();
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  logger.log('🧪 开始测试.up/.size/.down/.c指令顺序不敏感功能...');
  logger.log('📋 测试用例1：.up()和.size()顺序不同');
  logger.log('📋 用户代码（先up后size）:', userCode1);
  logger.log('📋 答案代码（先size后up）:', answerCode1);
  
  const result1 = validator.validate(userCode1, answerCode1, { isRegular: 0 });
  logger.log('🎯 测试用例1结果:', result1);
  logger.log('📊 相似度:', result1.similarity);
  logger.log('✅ 是否通过:', result1.isValid);
  
  // 测试用例2：.down()和.c()顺序不同
  const userCode2 = `int main(){
p.down();
p.c("red");
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  const answerCode2 = `int main(){
p.c("red");
p.down();
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  logger.log('📋 测试用例2：.down()和.c()顺序不同');
  logger.log('📋 用户代码（先down后c）:', userCode2);
  logger.log('📋 答案代码（先c后down）:', answerCode2);
  
  const result2 = validator.validate(userCode2, answerCode2, { isRegular: 0 });
  logger.log('🎯 测试用例2结果:', result2);
  logger.log('📊 相似度:', result2.similarity);
  logger.log('✅ 是否通过:', result2.isValid);
  
  // 测试用例3：多个指令顺序不同
  const userCode3 = `int main(){
p.up();
p.size(3);
p.down();
p.c("blue");
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  const answerCode3 = `int main(){
p.c("blue");
p.down();
p.size(3);
p.up();
p.fd(100);
p.rt(90);
p.fd(100);
return 0;
}`;
  
  logger.log('📋 测试用例3：多个指令顺序不同');
  logger.log('📋 用户代码（up->size->down->c）:', userCode3);
  logger.log('📋 答案代码（c->down->size->up）:', answerCode3);
  
  const result3 = validator.validate(userCode3, answerCode3, { isRegular: 0 });
  logger.log('🎯 测试用例3结果:', result3);
  logger.log('📊 相似度:', result3.similarity);
  logger.log('✅ 是否通过:', result3.isValid);
  
  return { result1, result2, result3 };
}

// 取消注释下面这行来运行测试
// testValidation();
// 导出CodeTrajectoryValidator类
// 测试C++风格代码解析（可以取消注释进行测试）
// const testValidator = new CodeTrajectoryValidator();
// const testCode = `int main(){
// for(int i=0;i<4;i++)
// pen.fd(100).rt(90);
// return 0;
// }`;
// logger.log('🧪 测试代码解析:', testValidator.preprocessCode(testCode));

export default CodeTrajectoryValidator;

// 也可以通过命名导出
export { CodeTrajectoryValidator };
